#include "Client.h"

Client::Client(string nick):log(CommonFunctions::GetLogName()){
	this->pid = getpid();
	this->nick = nick;
	this->connection = new Queue<message>(CommonFunctions::GetServerQueue().c_str(), 'a');
	this->groupChatId = 0;
	SignalHandler :: getInstance()->registrarHandler ( SIGINT,&sigint_handler );
	debug("Iniciando cliente");
}

void Client::run(){
	try {
		debug("Conectando con servidor");
		connectToServer();
		int choice;
		cout << " ===== Menu ===== " << endl;
		cout << "1. Iniciar nueva conversacion" << endl;
		cout << "2. Unirse a conversacion existente" << endl;
		cout << "3. Consultar conversaciones disponibles" << endl;
		cout << "4. Consultar usuarios existentes en conversacion" << endl;
		cout << "5. Salir de la conversacion actual" << endl;
		cout << "0. Salir" << endl;

		do {
			cin >> choice;
			switch (choice){
			case 0:
				disconnectFromServer();
				break;
			case 1:
				initMyGroupChat();
				break;
			case 2:
				joinToGroupChat();
				break;
			case 3:
				showActiveGroupsChat();
				break;
			case 4:
				showUsersGroupChat();
				break;
			case 5:
				leftGroupChat();
				break;
			default:
				cout << "Seleccione un numero del 0 al 5" << endl;
				break;
			}
		}
		while (choice != 0);
	} catch ( const char* mensaje ) {
		debug(mensaje);
	}
}



void Client::conversation(){
	cout<<endl;
	cout<<endl;
	cout << "Escriba mensaje:" << endl;

	SignalHandler::destruir();
	sigint_handler = *(new SIGINT_Handler());

	pid_t pidchild = fork();

	if (pidchild == 0){
		receiveMessages();
		exit(0);
	}
	else
	{
		sendMessages();
		kill(pidchild,SIGINT);
		wait(NULL);
		cin.clear();
		cout << "Abandonando sala..."<< endl;
		cout << endl;
	}
}

void Client::receiveMessages(){
	Queue<message>* queueMsg = new Queue<message>(CommonFunctions::GetClientQueue().c_str(), getppid());
	while (sigint_handler.getGracefulQuit() == 0) {
		message msg;
		debug("Esperando recibir mensaje del chat");
		if (queueMsg->read(RESPONSE, &msg) >0)
		cout << msg.text << endl;
	}
	debug("Finaliza recibir de mensajes");
}

void Client::sendMessages(){
	int response = 0;
	string txt;

	while ( sigint_handler.getGracefulQuit() == 0 )
	{
		char linea[100];
		cin.getline(linea, 100);
		string texto(linea);
		txt = "[" + nick + "]" + texto;

		if(!texto.empty()) {
			message msg, msgResp;
			msg.mtype = REQUEST;
			msg.commandId = CONVERSAR;
			msg.clientId = pid;
			msg.groupChatId = groupChatId;
			strcpy( msg.text , txt.c_str());

			debug("Envia al group chat " + CommonFunctions::ToString(groupChatId) + " el mensaje >> " + txt);
			response = connection->write(msg);
			debug("Envio mensaje exitosamente al grupo");

			connection->read(pid, &msgResp);
			debug("Recibio respuesta ACK");
		}
	}
	debug("Finaliza envio de mensajes");
	debug("El group Id sigue siendo " + CommonFunctions::ToString(groupChatId));
}

void Client::initMyGroupChat(){
	string name;
	cout<<"Ingrese el nombre de la conversacion:"<< endl;
	cin>>name;
	
	debug("Crear nuevo group chat con nombre " + name );

	message msgReq, msgResp;
	msgReq.mtype = REQUEST;
	msgReq.commandId = INICIAR_CONVERSACION;
	msgReq.clientId = pid;
	msgReq.groupChatId = groupChatId;
	strcpy( msgReq.text, name.c_str() );

	connection->write(msgReq);
	debug("Envio mensaje para INICIAR_CONVERSACION");
	connection->read(pid, &msgResp);
	debug("Recibio respuesta");

	if ( msgResp.commandId == OK ) {
		groupChatId = msgResp.groupChatId;
		chatName = name;
		debug("Participa del group chat con id " + CommonFunctions::ToString(groupChatId));
		conversation();
	}
}

void Client::joinToGroupChat(){
	
	if ( groupChatId != 0) {
		debug("Ingresa al chat room");
		conversation();
	}
	else
	{
		string groupChatName;
		cout << "Ingrese el identificador de la conversacion a la que desea unirse:" << endl;
		cin >> groupChatName;

		message msgReq, msgResp;
		msgReq.mtype = REQUEST;
		msgReq.commandId = UNIRSE_CONV;
		msgReq.clientId = pid;
		msgReq.groupChatId = groupChatId;
		strcpy( msgReq.text, groupChatName.c_str() );

		connection->write(msgReq);
		connection->read(pid, &msgResp);

		if ( msgResp.commandId == OK ) {
			groupChatId = msgResp.groupChatId;
			if ( groupChatId == 0 ){
				debug("No existe el group chat " + groupChatName );
			} else {
				debug("Participa del group chat " + groupChatName );
				chatName = groupChatName;
				conversation();
			}
		}
	}
}

void Client::leftGroupChat(){
	message msgReq, msgResp;
	msgReq.mtype = REQUEST;
	msgReq.commandId = DEJAR_CONV;
	msgReq.clientId = pid;
	msgReq.groupChatId = groupChatId;
	
	connection->write(msgReq);
	connection->read(pid, &msgResp);

	if ( msgResp.commandId == OK ) {
		cout << "Abandonando conversación " + CommonFunctions::ToString(groupChatId) + " "  + chatName <<endl;
		groupChatId = 0;
	}
}

void Client::showActiveGroupsChat(){
	debug("Envia peticion para ver los grupos activos");
	message msgReq, msgResp;
	msgReq.mtype = REQUEST;
	msgReq.commandId = CONV_ACTIVAS;
	msgReq.clientId = pid;
	msgReq.groupChatId = groupChatId;

	connection->write(msgReq);
	connection->read(pid, &msgResp);
	
	if ( msgResp.commandId == OK ) {
		cout << "Las conversaciones activas son: " << endl;
		cout << msgResp.text << endl;
		cout << endl;
		debug(" group chat " + CommonFunctions::ToString(groupChatId));
	}
}

void Client::showUsersGroupChat(){
	string groupChatName;
	cout << "Ingrese el identificador de la conversacion que desea consultar:" << endl;
	cin >> groupChatName;

	message msgReq, msgResp;
	msgReq.mtype = REQUEST;
	msgReq.commandId = PARTIC_ACTIVOS;
	msgReq.clientId = pid;
	msgReq.groupChatId = groupChatId;
	strcpy( msgReq.text, groupChatName.c_str() );
	
	debug("Haciendo peticion de PARTIC_ACTIVOS en el group chat " + groupChatName);
	connection->write(msgReq);
	connection->read(pid, &msgResp);
	
	if ( msgResp.commandId == OK ) {
		cout << "Los participantes conectados en " + groupChatName + " son: " << endl;
		cout << msgResp.text << endl;
		cout << endl;
	}
}

void Client::connectToServer(){
	message msgReq, msgResp;
	msgReq.mtype = REQUEST;
	msgReq.commandId = CONECTAR;
	msgReq.clientId = pid;
	msgReq.groupChatId = 0;
	strcpy( msgReq.text, nick.c_str() );

	connection->write(msgReq);
	connection->read(pid, &msgResp);

	if ( msgResp.commandId == OK ) {
		debug("Se conecto al servidor");
	}
}

void Client::disconnectFromServer(){
	if ( this->groupChatId != 0 ){
		leftGroupChat();
	}

	message msgReq, msgResp;
	msgReq.mtype = REQUEST;
	msgReq.commandId = DESCONECTAR;
	msgReq.clientId = pid;
	msgReq.groupChatId = groupChatId;
	strcpy( msgReq.text, nick.c_str() );

	connection->write(msgReq);
	debug("Envio solicitud para DESCONECTAR");
	connection->read(pid, &msgResp);

	if ( msgResp.commandId == OK ) {
		debug("Se desconecto del servidor");
	}
}

void Client::debug(string msg){
	log.debug("[" + CommonFunctions::ToString(pid) + "_" + nick + "]" + msg + "\n");
}

Client::~Client(){
	debug("Finalizando cliente");
	SignalHandler::destruir();
}


